package com.yao.myioc.factory.support;

import com.yao.myioc.aware.Aware;
import com.yao.myioc.aware.BeanFactoryAware;
import com.yao.myioc.definition.BeanDefinition;
import com.yao.myioc.definition.PropertyValue;
import com.yao.myioc.definition.RuntimeBeanReference;
import com.yao.myioc.definition.TypedStringValue;
import com.yao.myioc.factory.AutowiredCapableBeanFactory;
import com.yao.myioc.utils.ReflectUtils;

/**
 * @author Henry Yao
 */
public abstract class AbstractAutowiredCapableBeanFactory extends AbstractBeanFactory implements AutowiredCapableBeanFactory {
    /**
     * 这个方法既实现了com.yao.myioc.factory.AutowiredCapableBeanFactory#createBean也实现了
     * com.yao.myioc.factory.support.AbstractBeanFactory#createBean
     *
     * @param name
     * @param bd
     * @return
     */
    @Override
    public Object createBean(String name, BeanDefinition bd) {
        Object obj = null;
        try {
            // 1.获取bean实例类型
            Class<?> type = Class.forName(bd.getClazzName());
            // 2.反射创建bean对象
            obj = ReflectUtils.createObject(type, null);
            populateBean(bd, obj);
            initBean(bd, obj);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return obj;
    }

    private void initBean(BeanDefinition bd, Object obj) {
        // 4、执行aware接口方法
        if (obj instanceof Aware) {
            if (obj instanceof BeanFactoryAware) {
                ((BeanFactoryAware) obj).setBeanFactory(this);
            } else {
                // TODO: 2021/5/2 其他aware接口方法
            }
        }
        // 5.反射执行初始化方法
        String initMethod = bd.getInitMethod();
        if (initMethod != null) {
            ReflectUtils.invokeMethod(obj, bd.getInitMethod());
        }
    }


    private void populateBean(BeanDefinition bd, Object obj) {
        // 3.反射给属性赋值
        for (PropertyValue pv : bd.getPropertyValues()) {
            // 3-1 根据property的value类型分别进行处理
            Object value = pv.getValue();
            // 如果是基础数据类型的 直接赋值
            if (value instanceof TypedStringValue) {
                ReflectUtils.setProperty(obj, pv.getName(), ((TypedStringValue) value).getValue());
            } else {
                // 如果是引用类型的，则需要先获取引用的对象
                String ref = ((RuntimeBeanReference) value).getRef();
                Object bean = getBean(ref);
                ReflectUtils.setProperty(obj, pv.getName(), bean);
            }
        }
    }


}
